package cn.com.artemis.security.configuration;

import cn.com.artemis.security.*;
import cn.com.artemis.security.exceptions.AuthExceptionEntryPoint;
import cn.com.artemis.security.exceptions.CustomAccessDeniedHandler;
import cn.com.artemis.security.properties.OAuth2Properties;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandler;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
import org.springframework.security.oauth2.provider.token.store.JwtTokenStore;

/**
 * @Author enbool
 * @create 2020/6/15 13:40
 */
@Configuration
@EnableConfigurationProperties(OAuth2Properties.class)
public class SecurityAutoConfiguration {
    @Autowired
    private OAuth2Properties oAuth2Properties;

    @Bean
    @ConditionalOnMissingBean(UserDetailsService.class)
    public UserDetailsService userDetailsService(){
        return new DefaultUserDetailsService();
    }

    @Bean
    @ConditionalOnMissingBean(PermissionService.class)
    public PermissionService permissionService(){
        return new DefaultPermissionService();
    }

    @Bean
    @ConditionalOnMissingBean(PasswordEncoder.class)
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @ConditionalOnMissingBean(WhiteList.class)
    public WhiteList whiteList(){
        return new DefaultWhiteList();
    }

    @Bean
    public OAuth2WebSecurityExpressionHandler oAuth2WebSecurityExpressionHandler() {
        OAuth2WebSecurityExpressionHandler expressionHandler = new OAuth2WebSecurityExpressionHandler();
        return expressionHandler;
    }

    @Bean
    public TokenStore jwTokenStore() {
        return new JwtTokenStore(jwtAccessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter jwtAccessTokenConverter() {
        JwtAccessTokenConverter accessTokenConverter = new JwtAccessTokenConverter();
        accessTokenConverter.setSigningKey(oAuth2Properties.getJwtSigningKey());
        return accessTokenConverter;
    }

    @Bean
    public AuthExceptionEntryPoint authExceptionEntryPoint(ObjectMapper objectMapper){
        return new AuthExceptionEntryPoint(objectMapper);
    }

    @Bean
    public CustomAccessDeniedHandler customAccessDeniedHandler(ObjectMapper objectMapper){
        return new CustomAccessDeniedHandler(objectMapper);
    }

    @Bean
    public GrantTokenService grantTokenService(AuthorizationServerTokenServices tokenServices,
                                               PasswordEncoder passwordEncoder,
                                               ClientDetailsService clientDetailsService){

        return new GrantTokenService(tokenServices, passwordEncoder, clientDetailsService);
    }

    @Bean
    public RbacService rbacService(PermissionService permissionService, OAuth2Properties oAuth2Properties, WhiteList whiteList){
        return new RbacService(permissionService, oAuth2Properties, whiteList);
    }
}
